using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using TiaoTaoHelper.Http;

namespace HengTong.Model.Util
{
    /// <summary>
    /// HikVision HTTP工具类 - 基于HttpClient的现代化实现
    /// </summary>
    public class HikVisionHttpUtil
    {
        private static string _appKey;
        private static string _secret;
        private static string _ip;
        private static int _port = 443;
        private static bool _isHttps = true;

        /// <summary>
        /// 设置平台信息参数
        /// </summary>
        /// <param name="appKey">合作方APPKey</param>
        /// <param name="secret">合作方APPSecret</param>
        /// <param name="ip">平台IP</param>
        /// <param name="port">平台端口，默认HTTPS的443端口</param>
        /// <param name="isHttps">是否启用HTTPS协议，默认HTTPS</param>
        public static void SetPlatformInfo(string appKey, string secret, string ip, int port = 443, bool isHttps = true)
        {
            _appKey = appKey;
            _secret = secret;
            _ip = ip;
            _port = port;
            _isHttps = isHttps;
        }

        /// <summary>
        /// HTTP GET请求 - 异步版本
        /// </summary>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <returns></returns>
        public static async Task<byte[]> HttpGetAsync(string uri, int timeout = 30)
        {
            try
            {
                var headers = BuildRequestHeaders(uri, string.Empty, false);
                var url = BuildUrl(uri);

                // 重新创建HttpHelper实例以避免头部累积问题
                var httpHelper = new HttpHelper()
                    .SetTimeout(TimeSpan.FromSeconds(timeout))
                    .SetAllowAutoRedirect(false)
                    .SetAutomaticDecompression();

                if (_isHttps)
                {
                    httpHelper.SetIgnoreSslErrors();
                }

                // 添加自定义头部
                foreach (var header in headers.Where(h => h.Key.StartsWith("x-ca-")))
                {
                    httpHelper.AddHeader(header.Key, header.Value);
                }

                httpHelper.AddHeader("Accept", headers["Accept"])
                    .AddHeader("Content-Type", headers["Content-Type"]);

                var response = await httpHelper.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    return await response.Content.ReadAsByteArrayAsync();
                }

                // 处理重定向
                if (response.StatusCode == System.Net.HttpStatusCode.Found ||
                    response.StatusCode == System.Net.HttpStatusCode.Moved)
                {
                    var location = response.Headers.Location?.ToString();
                    if (!string.IsNullOrEmpty(location))
                    {
                        var redirectResponse = await httpHelper.GetAsync(location);
                        return await redirectResponse.Content.ReadAsByteArrayAsync();
                    }
                }

                return null;
            }
            catch (Exception ex)
            {
                // 记录异常日志
                Console.WriteLine($"HTTP GET请求异常: {ex.Message}");
                return null;
            }
        }

        /// HTTP POST请求 - 异步版本 (字符串请求体)
        /// </summary>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="body">请求参数(字符串)</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <returns>响应字节数组</returns>
        public static async Task<byte[]> HttpPostAsync(string uri, string body, int timeout = 30)
        {
            try
            {
                // 确保body不为null
                body = body ?? string.Empty;

                // 构建请求头和URL
                var headers = BuildRequestHeaders(uri, body, true);
                var url = BuildUrl(uri);

                // 设置SSL证书验证
                if (_isHttps)
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                        (sender, certificate, chain, errors) => true;
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |
                                                           SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
                }

                // 使用HttpClient
                using var httpClient = new HttpClient(new HttpClientHandler
                {
                    ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) => true
                })
                {
                    Timeout = TimeSpan.FromSeconds(timeout)
                };

                // 创建请求消息
                var request = new HttpRequestMessage(HttpMethod.Post, url);

                // 设置请求内容
                request.Content = new StringContent(body, Encoding.UTF8, "application/json");

                // 添加头部
                foreach (var header in headers.Where(h => h.Key.StartsWith("x-ca-") || h.Key == "content-md5"))
                {
                    request.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }

                // 发送请求
                var response = await httpClient.SendAsync(request);

                // 处理响应
                if (response.IsSuccessStatusCode)
                {
                    return await response.Content.ReadAsByteArrayAsync();
                }

                // 处理重定向
                if (response.StatusCode == HttpStatusCode.Found ||
                    response.StatusCode == HttpStatusCode.Moved)
                {
                    if (response.Headers.Location != null)
                    {
                        var redirectResponse = await httpClient.GetAsync(response.Headers.Location);
                        return await redirectResponse.Content.ReadAsByteArrayAsync();
                    }
                }

                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"HTTP POST请求异常: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// HTTP POST请求 - 异步版本 (对象请求体)
        /// </summary>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="requestObject">请求对象(会被序列化为JSON)</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <returns>响应字节数组</returns>
        public static async Task<byte[]> HttpPostAsync(string uri, object requestObject, int timeout = 30)
        {
            // 序列化对象为JSON字符串
            string jsonBody = requestObject == null ? "{}" : JsonSerializer.Serialize(requestObject);

            // 调用字符串版本的方法
            return await HttpPostAsync(uri, jsonBody, timeout);
        }


        /// <summary>
        /// HTTP GET请求 - 同步版本（保持向后兼容）
        /// </summary>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <returns></returns>
        public static byte[] HttpGet(string uri, int timeout = 30)
        {
            return HttpGetAsync(uri, timeout).GetAwaiter().GetResult();
        }

        /// <summary>
        /// HTTP POST请求 - 同步版本（保持向后兼容）
        /// </summary>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="body">请求参数</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <returns></returns>
        public static byte[] HttpPost(string uri, string body, int timeout = 30)
        {
            return HttpPostAsync(uri, body, timeout).GetAwaiter().GetResult();
        }

        /// <summary>
        /// HTTP GET请求并返回JSON对象
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <param name="options">JSON序列化选项</param>
        /// <returns></returns>
        public static async Task<T> HttpGetJsonAsync<T>(string uri, int timeout = 30,
            JsonSerializerOptions options = null)
        {
            var responseBytes = await HttpGetAsync(uri, timeout);
            if (responseBytes == null) return default(T);

            var json = Encoding.UTF8.GetString(responseBytes);
            options ??= new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<T>(json, options);
        }

        /// <summary>
        /// HTTP POST请求并返回JSON对象
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="body">请求参数</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <param name="options">JSON序列化选项</param>
        /// <returns></returns>
        public static async Task<T> HttpPostJsonAsync<T>(string uri, string body, int timeout = 30,
            JsonSerializerOptions options = null)
        {
            var responseBytes = await HttpPostAsync(uri, body, timeout);
            if (responseBytes == null) return default(T);

            var json = Encoding.UTF8.GetString(responseBytes);
            options ??= new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<T>(json, options);
        }
        

        /// <summary>
        /// 构建完整的请求URL
        /// </summary>
        /// <param name="uri">相对路径</param>
        /// <returns></returns>
        private static string BuildUrl(string uri)
        {
            var protocol = _isHttps ? "https" : "http";
            return $"{protocol}://{_ip}:{_port}{uri}";
        }

        /// <summary>
        /// 构建请求头信息
        /// </summary>
        /// <param name="uri">请求URI</param>
        /// <param name="body">请求体</param>
        /// <param name="isPost">是否为POST请求</param>
        /// <returns></returns>
        private static Dictionary<string, string> BuildRequestHeaders(string uri, string body, bool isPost)
        {
            var headers = new Dictionary<string, string>
            {
                ["Accept"] = "application/json",
                ["Content-Type"] = "application/json; charset=utf-8"
            };

            // 计算Content-MD5
            if (isPost && !string.IsNullOrWhiteSpace(body))
            {
                headers["content-md5"] = ComputeContentMd5(body);
            }

            // 时间戳
            string timestamp = ((DateTime.Now.Ticks - TimeZone.CurrentTimeZone.ToLocalTime(
                new DateTime(1970, 1, 1)).Ticks) / 10000).ToString();
            headers["x-ca-timestamp"] = timestamp;

            // 随机数
            headers["x-ca-nonce"] = Guid.NewGuid().ToString();
            headers["x-ca-key"] = _appKey;

            // 按照服务器期望的格式构建签名字符串
            StringBuilder sb = new StringBuilder();
            sb.Append(isPost ? "POST" : "GET").Append("\n");
            sb.Append(headers["Content-Type"]).Append("\n");
            sb.Append("x-ca-key:").Append(_appKey).Append('\n');
            sb.Append("x-ca-nonce:").Append(headers["x-ca-nonce"]).Append('\n');
            sb.Append("x-ca-timestamp:").Append(headers["x-ca-timestamp"]).Append('\n');
            sb.Append(uri);

            // 计算签名
            var signature = ComputeHmacSha256(sb.ToString(), _secret);
            headers["x-ca-signature"] = signature;
            headers["x-ca-signature-headers"] = "x-ca-key,x-ca-nonce,x-ca-timestamp";

            return headers;
        }

        

        /// <summary>
        /// HTTP POST请求并返回JSON对象 - 直接传递对象
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="uri">HTTP接口Url，不带协议和端口</param>
        /// <param name="requestObject">请求对象</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <param name="options">JSON序列化选项</param>
        /// <returns></returns>
        public static async Task<T> HttpPostJsonAsync<T>(string uri, object requestObject, int timeout = 30,
            JsonSerializerOptions options = null)
        {
            var responseBytes = await HttpPostAsync(uri, requestObject, timeout);
            if (responseBytes == null) return default(T);

            var json = Encoding.UTF8.GetString(responseBytes);
            options ??= new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<T>(json, options);
        }


        /// <summary>
        /// 计算Content-MD5值
        /// </summary>
        /// <param name="body">请求体内容</param>
        /// <returns></returns>
        private static string ComputeContentMd5(string body)
        {
            using var md5 = MD5.Create();
            var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(body));
            return Convert.ToBase64String(hash);
        }

        /// <summary>
        /// 计算HMAC-SHA256签名
        /// </summary>
        /// <param name="data">待签名数据</param>
        /// <param name="key">签名密钥</param>
        /// <returns></returns>
        private static string ComputeHmacSha256(string data, string key)
        {
            using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
            var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
            return Convert.ToBase64String(hash);
        }

        /// <summary>
        /// 构建签名字符串
        /// </summary>
        /// <param name="method">HTTP方法</param>
        /// <param name="uri">请求URI</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        private static string BuildSignString(string method, string uri, Dictionary<string, string> headers)
        {
            // 完全复制官方buildSignString实现
            StringBuilder sb = new StringBuilder();
            sb.Append(method.ToUpper()).Append("\n");
            if (headers != null)
            {
                // 注意这里的键名大小写
                if (headers.ContainsKey("Accept") && headers["Accept"] != null)
                    sb.Append(headers["Accept"]);
                sb.Append("\n");

                if (headers.ContainsKey("Content-MD5") && headers["Content-MD5"] != null)
                    sb.Append(headers["Content-MD5"]);
                sb.Append("\n");

                if (headers.ContainsKey("Content-Type") && headers["Content-Type"] != null)
                    sb.Append(headers["Content-Type"]);
                sb.Append("\n");

                if (headers.ContainsKey("Date") && headers["Date"] != null)
                    sb.Append(headers["Date"]);
                sb.Append("\n");
            }

            // 使用与官方完全一致的BuildSignHeader实现
            string signHeader = BuildSignHeaders(headers);
            sb.Append(signHeader);
            sb.Append(uri);
            return sb.ToString();
        }


        /// <summary>
        /// 构建签名头部字符串 - 与原版HttpUtillib.cs保持完全一致
        /// </summary>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        private static string BuildSignHeaders(Dictionary<string, string> headers)
        {
            // 按键名排序 - 与原版保持一致
            var sortedHeaders = headers.OrderBy(kvp => kvp.Key).ToList();

            var sbSignHeader = new StringBuilder();
            var sb = new StringBuilder();

            foreach (var kvp in sortedHeaders)
            {
                // 修复：添加与原版完全一致的空格处理逻辑
                if (kvp.Key.Replace(" ", "").Contains("x-ca-"))
                {
                    sb.Append(kvp.Key + ":");
                    if (!string.IsNullOrWhiteSpace(kvp.Value))
                    {
                        sb.Append(kvp.Value);
                    }

                    sb.Append("\n");

                    if (sbSignHeader.Length > 0)
                    {
                        sbSignHeader.Append(",");
                    }

                    sbSignHeader.Append(kvp.Key);
                }
            }

            // 添加x-ca-signature-headers到headers中
            headers["x-ca-signature-headers"] = sbSignHeader.ToString();

            return sb.ToString();
        }
    }
}